/* 
 * Copyright (c) 2012 JSquirrelEngine
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in 
 * the Software without restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 */

package org.jsquirrel.math;


/**
 * Class representing a 2D mathematical vector. The values of the coordinates are stored on
 * float variables.
 * 
 * @author Juan David Adarve Bermudez 
 *
 */
public class F2Vector {

	//*********************************************************************************************
	// INSTANCE ATTRIBUTES
	//*********************************************************************************************
	
	/**
	 * X vector coordinate
	 */
	public float x;
	
	/**
	 * Y vector coordinate
	 */
	public float y;
	
	
	//*********************************************************************************************
	// CONSTRUCTORS
	//*********************************************************************************************
	
	/**
	 * Creates an instance with zero coordinates
	 */
	public F2Vector() {
		
		x = 0.0f;
		y = 0.0f;
	}
	
	/**
	 * Creates a vector with the given coordinates
	 * 
	 * @param x: X coordinate
	 * @param y: Y coordinate
	 */
	public F2Vector(float x, float y) {
		
		this.x = x;
		this.y = y;
	}
	
	/**
	 * Creates a vector with the coordinates given another F2Vector instance. If the
	 * argument is null, the behavior of this constructor is undefined 
	 * 
	 * 
	 * @param vector: F2Vector instance from which the coordinates values are taken
	 */
	public F2Vector(final F2Vector vector) {
		
		this.x = vector.x;
		this.y = vector.y;
	}
	
	
	//*********************************************************************************************
	// PUBLIC METHODS
	//*********************************************************************************************
	
	/**
	 * Returns the vector X coordinate
	 * 
	 * @return vector X coordinate
	 */
	public final float x() {
		return x;
	}
	
	/**
	 * Set the X coordinate to a new value
	 * 
	 * @param x: new value for the X coordinate
	 */
	public final void setX(float x) {
		this.x = x;
	}
	
	/**
	 * Returns the vector Y coordinate
	 * 
	 * @return vector Y coordinate
	 */
	public final float y() {
		return y;
	}
	
	/**
	 * Set the Y coordinate to a new value
	 * 
	 * @param y: new value for the Y coordinate
	 */
	public final void setY(float y) {
		this.y = y;
	}	
	
	/**
	 * Returns a String with the form "(x, y)" with the
	 * coordinates of this vector
	 * 
	 * @return String with the coordinate values of this vector
	 */
	public String toString() {
		return "(" + x() + ", " + y() + ")";
	}
	
	/**
	 * Performs the addition of this vector with another F2Vector instance. If such
	 * instance is null, the behavior of this function is undefined. The result of
	 * the sum is stored on this instance.
	 * 
	 * @param vector: vector to be added to this
	 */
	public final void add(final F2Vector vector) {
		x += vector.x;
		y += vector.y;
	}
	
	/**
	 * Computes the dot product between this vector an the one given as parameter.
	 * If the parameter is null, the behavior is undefined.
	 * 
	 * @param vector: other vector to compute the dot product
	 * 
	 * @return value of the dot product between the two vectors
	 */
	public final float dotProduct(final F2Vector vector) {
		return x*vector.x + y*vector.y;
	}
	
	/**
	 * Computes the dot product between this vector and another one represented as
	 * two float parameters
	 * 
	 * @param x: X coordinate for the other vector
	 * @param y: Y coordinate for the other vector
	 * 
	 * 
	 * @return value of the dot product between the two vectors
	 */
	public final float dotProduct(float x, float y) {
		
		return this.x*x + this.y*y;
	}
	
	/**
	 * Performs the scalar product on this vector
	 * 
	 * @param scalar: scalar value
	 */
	public final void scalarProduct(float scalar) {
		x *= scalar;
		y *= scalar;
	}
	
	/**
	 * Returns the mathematical length of this vector
	 * 
	 * @return vector length
	 */
	public final float length() {
		return (float)Math.sqrt(x*x + y*y);
	}
	
	/**
	 * Normalizes this vector such that its length is equal to 1.0
	 */
	public final void normalize() {
		float norm = length();
		x /= norm;
		y /= norm;
	}
	
	
	//*********************************************************************************************
	// PUBLIC STATIC METHODS
	//*********************************************************************************************
	
	/**
	 * Performs the addition between two vectors and stores the result on a third one. If some of
	 * the parameters is null, the behavior of this method is undefined.
	 * 
	 * @param v1: first vector to add
	 * @param v2: second vector to add
	 * @param result: stores the result of the addition
	 */
	public static void add(final F2Vector v1, final F2Vector v2, F2Vector result) {
		result.x = v1.x + v2.x;
		result.y = v1.y + v2.y;
	}
	
	/**
	 * Performs the subtraction between two vectors and stores the result on a third one. If some of
	 * the parameters is null, the behavior of this method is undefined.
	 * 
	 * @param minuend: vector minuend
	 * @param subtrahend: vector subtrahend
	 * @param result: result of the subtraction
	 */
	public static void sub(final F2Vector minuend, final F2Vector subtrahend, F2Vector result) {
		
		result.x = minuend.x - subtrahend.x;
		result.y = minuend.y - subtrahend.y;
	}	
	
	/**
	 * Returns the distance between two vectors. If some of the parameters is null then
	 * the behavior of this method is undefined
	 * 
	 * @param v1
	 * @param v2
	 * 
	 * @return distance between the two vectors
	 */
	public static float distanceBetween(final F2Vector v1, final F2Vector v2) {
		
		float x = v1.x - v2.x;
		float y = v1.y - v2.y;
		
		return (float)Math.sqrt(x*x + y*y);
	}
	
	/**
	 * Returns the distance between two vectors, each represented as two parameters for the
	 * coordinates.
	 * 
	 * @param x1: X coordinate for the first vector
	 * @param y1: Y coordinate for the first vector
	 * @param x2: X coordinate for the second vector
	 * @param y2: Y coordinate for the second vector
	 * 
	 * @return distance between the two vectors
	 */
	public static float distanceBetween(float x1, float y1, float x2, float y2) {
		float x = x1 - x2;
		float y = y1 - y2;
		
		return (float)Math.sqrt(x*x + y*y);
	}
	
	/**
	 * Computes a perpendicular vector of a given F2Vector parameter and stores the
	 * result into another instance. This is done by applying a 90 degrees rotation
	 * on the source vector. If some of the parameters is null, the behavior of this
	 * method is undefined.
	 * 
	 * @param source: source vector
	 * @param result: stores a perpendicular vector to source
	 */
	public static void perpendicularVector(final F2Vector source, F2Vector result) {
		
		float x = -source.y;
		float y = source.x;
		
		result.x = x;
		result.y = y;
	}
}
